// Copyright 2012 Google Inc. All Rights Reserved.
package com.google.appengine.syncserver.endpoint;

import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiFrontendLimits;
import com.google.api.server.spi.config.ApiMethod;
import com.google.appengine.syncserver.processor.AbstractProcessor;
import com.google.appengine.syncserver.processor.ClientIdProcessor;
import com.google.appengine.syncserver.processor.ReadProcessor;
import com.google.appengine.syncserver.processor.WriteProcessor;
import com.google.appengine.syncserver.shared.HttpParameterDefinitions;
import com.google.appengine.syncserver.shared.HttpParameterDefinitions.ClientRequest;
import com.google.appengine.syncserver.shared.WriteUpdatesPageRequest;
import com.google.appengine.syncserver.shared.WriteUpdatesResponse;

/**
 * Cloud End Point for sync. The developer can modify the annotations to fine tune
 * Cloud EndPoints.
 */
@Api(name = "syncendpoint", frontendLimits
    = @ApiFrontendLimits(unregisteredQps = -1, unregisteredUserQps = -1, unregisteredDaily = -1))
public class SyncEndpoint {
  
  private static final String SYNC_UPDATE_MESSAGE = "Server updated";
  private static final Logger log = Logger.getLogger(SyncEndpoint.class.getName());

@ApiMethod(httpMethod = "POST")
  public Response getSyncResponse(Request request) {
    Response resp = new Response();
    if (request.getRequestType() == null) {
      resp.setInternalServerError(true);
      return resp;
    }

    AbstractProcessor processor;

    HttpParameterDefinitions.ClientRequest clientRequest =
        HttpParameterDefinitions.ClientRequest.valueOf(request.getRequestType());
    switch (clientRequest) {
      case CLIENT_ID_REQUEST:
        processor = new ClientIdProcessor();
        break;
      case READ_REQUEST:
        processor = new ReadProcessor();
        break;
      case WRITE_REQUEST:
        processor = new WriteProcessor();
        break;
      default:
        resp.setInternalServerError(true);
        return resp;
    }
    
    resp = processor.processSwarmRequest(request);
    sendGCMUpdates(request, resp);
    return resp;
  }

  private void sendGCMUpdates(Request request, Response resp) {
      HttpParameterDefinitions.ClientRequest clientRequest =
              HttpParameterDefinitions.ClientRequest.valueOf(request.getRequestType());

	  if (clientRequest != ClientRequest.WRITE_REQUEST) {
	    return;
	  }
	
	  // On error just return response.
	  if (resp.getConflict() || resp.getInternalServerError()) {
	    return;
	  }
	
	  WriteUpdatesPageRequest writePage = null;
	  try {
	    writePage = WriteUpdatesPageRequest.valueOf(request.getPayload());
	  } catch (Throwable e) {
		log.log(Level.SEVERE, e.getMessage(), e);
	    return;
	  }
	
	  if (!writePage.isLastPage()) {
	    return;
	  }
	
	  WriteUpdatesResponse writeResponse = WriteUpdatesResponse.valueOf(resp.getResponseStr());
	  if (writeResponse.getMaxVersion() != writePage.getMaxVersion()) {
	    try {
	      DevicePing.pingAllDevices(SYNC_UPDATE_MESSAGE, writePage.getUsername(),
	        writePage.getGCMRegistrationId());
	    } catch(Throwable e) {
	      log.log(Level.WARNING, e.getMessage(), e);
	      return;
	    }
	  }
	  return;
  }
}
